home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / shells / flin-0.5 / flin-0 / flin-0.5.1 / screens / ncurses.c < prev   
C/C++ Source or Header  |  1996-04-26  |  10KB  |  459 lines

  1. /*
  2.    Displays menu and takes input
  3.    Copyright (C) 1995, 1996  Brian Cully
  4.  
  5.    This program is free software; you can redistribute it and/or modify it under
  6.    the terms of the GNU General Public License as published by the Free Software
  7.    Foundation; either version 2 of the License, or (at your option) any later
  8.    version.
  9.  
  10.    This program is distributed in the hope that it will be useful, but WITHOUT
  11.    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12.    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
  13.    details.
  14.  
  15.    You should have received a copy of the GNU General Public License along with
  16.    this program; if not, write to the Free Software Foundation, Inc., 675 Mass
  17.    Ave, Cambridge, MA 02139, USA.
  18.  
  19.    please send patches (w/ explanation) or advice to: `shmit@kublai.com'
  20.  */
  21. #ifdef HAVE_CONFIG_H
  22. #include <config.h>
  23. #endif
  24.  
  25. #ifdef HAVE_NCURSES_NCURSES_H
  26. #include <ncurses/ncurses.h>
  27. #else
  28. #include <curses.h>
  29. #endif
  30.  
  31. #include <signal.h>
  32. #include <unistd.h>
  33. #include <termios.h>
  34.  
  35. #include "ncr_scr.h"
  36. #include "../screen.h"
  37. #include "../misc.h"
  38. #include "../exec.h"
  39. #include "../menu.h"
  40.  
  41. bool color;
  42. char draw_box = 1;
  43. extern struct menu *main_menu;
  44. extern int noclobber;
  45.  
  46. static void setup_colors() {
  47.    init_pair(MENU_TITLE + 1, TITLE_COL, BG_COL);
  48.    init_pair(MENU_NOP + 1, NOP_COL, BG_COL);
  49.    init_pair(MENU_EXEC + 1, EXEC_COL, BG_COL);
  50.    init_pair(MENU_ARGS + 1, ARGS_COL, BG_COL);
  51.    init_pair(MENU_SUB + 1, SUB_COL, BG_COL);
  52.    init_pair(MENU_EXIT + 1, EXIT_COL, BG_COL);
  53.    init_pair(MENU_QUIT + 1, QUIT_COL, BG_COL);
  54. }
  55.  
  56. /* Interface to main module
  57.    Initialize the screen, must be called before anything else */
  58. void init_scr() {
  59.    sigset_t newmask, oldmask;
  60.  
  61.    /*
  62.  
  63.       It looks as if initscr resets the default signal handlers. Block sigint, sigquit  
  64.       and sigtstp until after we are through, then quickly ignore them and allow signals
  65.       through again 
  66.     */
  67.  
  68.    sigemptyset(&newmask);
  69.    sigemptyset(&oldmask);
  70.  
  71.    sigaddset(&newmask, SIGINT);
  72.    sigaddset(&newmask, SIGTSTP);
  73.    sigaddset(&newmask, SIGQUIT);
  74.  
  75.    sigprocmask(SIG_BLOCK, &newmask, &oldmask);
  76.  
  77.    initscr();
  78.  
  79.    if ((color = has_colors())) {
  80.       start_color();
  81.       setup_colors();
  82.    }
  83.    cbreak();
  84.    noecho();
  85.    keypad(stdscr, TRUE);
  86.  
  87.    signal(SIGINT, SIG_IGN);
  88.    signal(SIGTSTP, SIG_IGN);
  89.    signal(SIGQUIT, SIG_IGN);
  90.  
  91.    sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *) NULL);
  92. }
  93.  
  94. /* Interface to main module
  95.    Close the output, must be called when finished */
  96. void close_scr() {
  97.    endwin();
  98. }
  99.  
  100. void write_str(char *s) {
  101.    int row, col;
  102.  
  103.    getyx(stdscr, row, col);
  104.    mvaddstr(row, col, s);
  105.    refresh();
  106. }
  107.  
  108. void clear_scr() {
  109.    attrset(A_NORMAL);
  110.    erase();
  111.    refresh();
  112. }
  113.  
  114. int readchar() {
  115.    return getch();
  116. }
  117.  
  118. static void draw_dialog(WINDOW ** b_win, WINDOW ** win, char *title, int len) {
  119.    int i;
  120.  
  121.    *b_win = newwin(3, len + 2, 1, 0);
  122.    box(*b_win, 0, 0);
  123.    mvwaddstr(*b_win, 0, (len - strlen(title)) / 2 - 1, title);
  124.    wrefresh(*b_win);
  125.  
  126.    *win = derwin(*b_win, 1, len, 1, 1);
  127.    for (i = 0; i < len; i++)
  128.       waddch(*win, ' ');
  129. }
  130.  
  131. static void clear_wins(WINDOW **b_win, WINDOW **win) {
  132.    if (!draw_box) {
  133.       werase(*win);
  134.       wrefresh(*win);
  135.    }
  136.    delwin(*win);
  137.    if (draw_box)
  138.       delwin(*b_win);
  139. }
  140.  
  141. int get_args(char *args, char *title) {
  142.    WINDOW *b_win, *win;
  143.    struct termios term;
  144.    int c;
  145.    cc_t erase = 0, kill = 0;
  146.    int i = 0;
  147.  
  148.    if (tcgetattr(0, &term) >= 0) {
  149.       erase = term.c_cc[VERASE];
  150.       kill = term.c_cc[VKILL];
  151.    }
  152.    draw_dialog(&b_win, &win, title, 78);
  153.    waddch(win, ' ');
  154.    mvwdelch(win, 0, 0);
  155.    wmove(win, 0, 0);
  156.    wrefresh(win);
  157.  
  158.    while ((c = wgetch(win)) != '\n' && c != ESCAPEKEY) {
  159.       if ((c == erase) || (c == KEY_BACKSPACE)) {
  160.      if (i > 0) {
  161.         i--;
  162.         mvwdelch(win, 0, i);
  163.      }
  164.       } else if (c == kill) {
  165.      wmove(win, 0, 0);
  166.      i = 0;
  167.      wclrtoeol(win);
  168.       } else if (c == '\014')    /* ctrl-l */
  169.      wrefresh(curscr);
  170.       else {
  171.      waddch(win, c);
  172.      *(args + i) = c;
  173.      i++;
  174.       }
  175.       wrefresh(win);
  176.    }
  177.    if (c == ESCAPEKEY)
  178.       return 1;
  179.    
  180.    *(args + i) = '\0';
  181.  
  182.    clear_wins(&b_win, &win);
  183.    return 0;
  184. }
  185.  
  186. static void display_items(WINDOW * win, struct menu_items src, int cols, int hilite) {
  187.    int lenstr, i;
  188.  
  189.    wattrset(win, hilite ? A_REVERSE : A_BOLD);
  190.    if (color)
  191.       wattron(win, COLOR_PAIR((src.type + 1)));
  192.  
  193.    switch (src.type) {
  194.    case MENU_TITLE:
  195.       for (i = 0; i < (cols - strlen(src.name)) / 2; i++)
  196.      waddch(win, ' ');
  197.       waddstr(win, src.name);
  198.       break;
  199.  
  200.    case MENU_SUB:
  201.       waddch(win, '<');
  202.       waddstr(win, src.name);
  203.       waddch(win, '>');
  204.       break;
  205.  
  206.    case MENU_NOP:
  207.       wattroff(win, hilite ? A_REVERSE : A_BOLD);
  208.       if (strlen(src.name) > 1)
  209.      waddstr(win, src.name);
  210.       else
  211.      whline(win, ACS_HLINE, cols);
  212.       break;
  213.  
  214.    default:
  215.       waddstr(win, src.name);
  216.       break;
  217.    }
  218.  
  219.    lenstr = strlen(src.name);
  220.    if (lenstr > 0) {
  221.       lenstr += (src.type == MENU_TITLE) ? (cols - lenstr) / 2 : ((src.type == MENU_SUB) ? 2 : 0);
  222.       for (i = cols; i > lenstr; i--)
  223.      waddch(win, ' ');
  224.    }
  225. }
  226.  
  227. static void draw_menu(WINDOW * win, int nlines, int ncols, struct menu_items *items, int *row) {
  228.    int i;
  229.    struct menu_items *p = items;
  230.  
  231.    for (i = 0; i <= nlines; i++) {
  232.       if (p) {
  233.      wmove(win, i, 0);
  234.      display_items(win, *p, ncols, FALSE);
  235.      p = p->next;
  236.       }
  237.    }
  238. }
  239.  
  240. static void draw_status_bar() {
  241.    int i;
  242.  
  243.    attrset(A_REVERSE);
  244.    mvaddstr(0, 0, TOP_BAR);
  245.    for (i = strlen(TOP_BAR); i < COLS; i++)
  246.       addch(' ');
  247.    mvaddstr(LINES - 1, 0, BOT_BAR);
  248.    for (i = strlen(BOT_BAR); i < COLS; i++)
  249.       addch(' ');
  250. }
  251.  
  252. /* Go down at least one row, skipping comments (MENU_NOP) and titles (MENU_TITLE)
  253.    *row == a pointer to the current row
  254.    **p == menu item list to sort through and display */
  255. static void down_hilite(WINDOW * win, int *row, int cols, struct menu_items **p) {
  256.    int back_row = *row;
  257.    struct menu_items *back_item = *p;
  258.    bool quit = FALSE;
  259.  
  260.    /* redisplay the first row */
  261.    wmove(win, *row, 0);
  262.    display_items(win, **p, cols, FALSE);
  263.  
  264.    /* advance until past titles and menus or end of menus */
  265.    while ((*p)->next && !quit) {
  266.       *p = (*p)->next;
  267.       (*row)++;
  268.       switch ((*p)->type) {
  269.       case MENU_TITLE:
  270.       case MENU_NOP:
  271.      break;
  272.       default:
  273.      quit = TRUE;
  274.      break;
  275.       }
  276.    }
  277.  
  278.    /* if menu end was hit without finding a hilitable item, go back to original row */
  279.    if (!quit) {
  280.       *row = back_row;
  281.       *p = back_item;
  282.    }
  283.    wmove(win, *row, 0);
  284.    display_items(win, **p, cols, TRUE);
  285.    wrefresh(win);
  286. }
  287.  
  288. /* see down_hilite and reverse the direction */
  289. static void up_hilite(WINDOW * win, int *row, int cols, struct menu_items **p) {
  290.    int back_row = *row;
  291.    struct menu_items *back_item = *p;
  292.    bool quit = FALSE;
  293.  
  294.    wmove(win, *row, 0);
  295.    display_items(win, **p, cols, FALSE);
  296.  
  297.    while ((*p)->prev && !quit) {
  298.       *p = (*p)->prev;
  299.       (*row)--;
  300.       switch ((*p)->type) {
  301.       case MENU_TITLE:
  302.       case MENU_NOP:
  303.      break;
  304.       default:
  305.      quit = TRUE;
  306.      break;
  307.       }
  308.    }
  309.  
  310.    if (!quit) {
  311.       *row = back_row;
  312.       *p = back_item;
  313.    }
  314.    wmove(win, *row, 0);
  315.    display_items(win, **p, cols, TRUE);
  316.    wrefresh(win);
  317. }
  318.  
  319. static void init_list(WINDOW ** win, WINDOW ** bwin, struct menu_items **items, int *nitems,
  320.               int *nlines, int *ncols, int *row) {
  321.    struct menu_items *p = *items, *q;
  322.  
  323.    *nitems = 0;
  324.    *ncols = 0;
  325.  
  326.    draw_status_bar();
  327.    refresh();
  328.  
  329.    while (p->prev)
  330.       p = p->prev;
  331.  
  332.    q = p;
  333.  
  334.    while (q) {
  335.       int i;
  336.  
  337.       if ((i = strlen(q->name) +
  338.        ((q->type == MENU_SUB) ? 2 : ((q->type == MENU_TITLE) ? 2 : 0))) > *ncols)
  339.      *ncols = i;
  340.       (*nitems)++;
  341.       q = q->next;
  342.    }
  343.  
  344.    *nlines = (*nitems < LINES) ? (*nitems) : LINES;
  345.    *ncols = (*ncols < COLS) ? (*ncols) : COLS;
  346.  
  347.    if (draw_box) {
  348.       if ((*bwin = newwin((*nlines)+2, (*ncols)+2,
  349.               (LINES - *nlines)/2 - 1,
  350.               (COLS - *ncols)/2 - 1)) == NULL)
  351.       error("Couldn't create border window", 0);
  352.  
  353.       box(*bwin, 0, 0);
  354.       wrefresh(*bwin);
  355.   
  356.       if ((*win = derwin(*bwin, *nlines, *ncols, 1, 1)) == NULL)
  357.      error("Couldn't create main window", 0);
  358.    } else {
  359.       if ((*win = newwin(*nlines, *ncols, (LINES - *nlines)/2, (COLS - *ncols)/2)) == NULL)
  360.      error("Couldn't create main window", 0);
  361.    }
  362.  
  363.    draw_menu(*win, *nlines, *ncols, p, row);
  364.  
  365.    if (((*items)->type == MENU_TITLE) || ((*items)->type == MENU_NOP))
  366.       down_hilite(*win, row, *ncols, items);
  367.    else {
  368.       wmove(*win, *row, 0);
  369.       display_items(*win, **items, *ncols, TRUE);
  370.    }
  371.  
  372.    wrefresh(*win);
  373. }
  374.  
  375. void display_list(struct menu *menu_list) {
  376.    struct menu_items *p = menu_list->data;
  377.    int win_lines, win_cols, n_items, row = 0, quit = 0, dontclobber = 0;
  378.    WINDOW *win, *b_win;
  379.  
  380.    if (!(menu_list))
  381.       return;
  382.  
  383.    dontclobber = ((noclobber) && (menu_list == main_menu));
  384.  
  385.    init_list(&win, &b_win, &p, &n_items, &win_lines, &win_cols, &row);
  386.    refresh();
  387.  
  388.    while (!quit) {
  389.       switch (getch()) {
  390.       case KEY_LEFT:
  391.       case 2:
  392.      if (!dontclobber) {
  393.         attrset(A_NORMAL);
  394.         erase();
  395.         refresh();
  396.         quit = TRUE;
  397.      }
  398.      break;
  399.  
  400.       case KEY_RIGHT:
  401.       case '\n':
  402.       case 6:
  403.      switch (p->type) {
  404.      case MENU_EXIT:
  405.         attrset(A_NORMAL);
  406.         erase();
  407.         refresh();
  408.         quit = TRUE;
  409.         break;
  410.  
  411.      case MENU_QUIT:
  412.         clear_wins(&b_win, &win);
  413.         attrset(A_NORMAL);
  414.         erase();
  415.         refresh();
  416.         close_scr();
  417.         exit(0);
  418.  
  419.      default:
  420.         clear_wins(&b_win, &win);
  421.         exec_item(*p, &menu_list);
  422.         init_list(&win, &b_win, &p, &n_items, &win_lines, &win_cols, &row);
  423.         break;
  424.      }
  425.      break;
  426.  
  427.       case KEY_DOWN:
  428.       case 14:
  429.      down_hilite(win, &row, win_cols, &p);
  430.      break;
  431.  
  432.       case KEY_UP:
  433.       case 16:
  434.      up_hilite(win, &row, win_cols, &p);
  435.      break;
  436.  
  437.       case 'g':
  438.       case 'G':
  439.      clear_wins(&b_win, &win);
  440.      display_file(PATH_TO_GPL);
  441.      init_list(&win, &b_win, &p, &n_items, &win_lines, &win_cols, &row);
  442.      break;
  443.  
  444.       case 'h':
  445.       case 'H':
  446.      clear_wins(&b_win, &win);
  447.      display_file(PATH_TO_HELP);
  448.      init_list(&win, &b_win, &p, &n_items, &win_lines, &win_cols, &row);
  449.      break;
  450.       case 'F':
  451.       case 'f':
  452.       case 12:
  453.      wrefresh(curscr);
  454.      break;
  455.       }
  456.    }
  457.    clear_wins(&b_win, &win);
  458. }
  459.